package com.fantastic.common.utils;

import com.fantastic.common.exception.DataCheckException;
import com.fantastic.common.exception.FileTypeException;
import com.fantastic.common.exception.enums.RespStatusInfo;
import org.apache.commons.io.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Calendar;
import java.util.UUID;

/**
 * @author: rxx
 * @since: 2024/5/28 20:16
 * @description: 文件上传工具类
 * 对前端过来的文件进行二次处理
 */
public class MultipartFileUtils {

    /**
     * 图片存储的本地地址（genshen专属）
     */
    private static final String FILE_PATH = "D:\\image-server\\";


    /**
     * 支持的文件类型
     */
    private static final String[] SUPPORT_FILE_TYPE = {".jpg", ".png", ".gif"};

    /**
     * 查看文件格式是否支持上传
     *
     * @param fileSuffix 文件格式如：.jpg
     */
    public static void supportType(String fileSuffix) {
        fileSuffix = getSuffix(fileSuffix);
        if (fileSuffix != null) {
            boolean isSupported = false;
            for (int i = 0; i < SUPPORT_FILE_TYPE.length; i++) {
                if (SUPPORT_FILE_TYPE[i].equals(fileSuffix)) {
                    isSupported = true;
                    //有支持，极跳出循环
                    break;
                }
            }
            if (!isSupported) {
                //如果循环结束后仍未找到支持的文件类型，则抛出异常
                throw new FileTypeException(RespStatusInfo.FILETYPE_ERROR);
            }
        } else {
            //抛出数据不符合规范异常
            throw new DataCheckException(RespStatusInfo.DATA_ERROR);
        }

    }

    /**
     * 单独文件上传到本地目录中，返回文件存储的相对路径，以供后面保存到数据库中。
     *
     * @param file
     * @param pictureType 图片类型（选值为套餐、头像、菜品）
     * @return 返回文件存储的相对路径，
     * file.getOriginalFilename()：获取上传文件本来的文件名
     */
    public static String writeFile(MultipartFile file, String pictureType) {
        try {
            //1、获取当前上传的文件的输入流
            InputStream inputStream = file.getInputStream();
            //2、获取文件要存储的绝对路径。
            //createUUID()是创建一个随机字符串，用作文件名。 getSuffix()是获取文件的后缀
            String ap = createDateDirectory(pictureType) + createUUID() + getSuffix(file.getOriginalFilename());
            //3、获得上传文件位置的输出流
            OutputStream outputStream = Files.newOutputStream(Paths.get(ap));
            //4、执行文件拷贝
            IOUtils.copy(inputStream, outputStream);
            //5、关闭流资源
            outputStream.close();
            //返回文件名。将绝对路径的前半段替换成""
            return ap.replace(FILE_PATH, "");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 多文件上传到本地目录中，返回文件存储的相对路径，以供后面保存到数据库中。
     *
     * @param file
     * @param pictureType 图片类型
     * @return 返回文件存储的相对路径，以供后面保存到数据库中。
     * file.getOriginalFilename()：获取上传文件本来的文件名
     */
    public static String[] writeFiles(MultipartFile[] file, String pictureType) {
        //创建一个String数组，用于存储文件在本地的相对路径
        String[] fileRelativePaths = new String[file.length];
        //遍历MultipartFile数组
        for (int i = 0; i < file.length; i++) {
            String s = writeFile(file[i], pictureType);
            fileRelativePaths[i] = s;
        }
        //返回存储好的路径数组
        return fileRelativePaths;
    }

    /**
     * 删除单个的本地的文件
     *
     * @param filePath 文件的相对路径
     * @return 删除成功返回true。否则false
     */
    public static boolean deleteFile(String filePath) {
        //创建路径对象。拼凑出完整的文件绝对路径
        Path ap = Paths.get(FILE_PATH + filePath);
        //判断文件是否存在
        if (Files.exists(ap)) {
            //文件存在进行删除
            FilesUtils.delete(ap);
        }
        return true;
    }

    /**
     * 批量删除本地的文件
     *
     * @param filePath
     * @return
     */
    public static boolean deleteFiles(String[] filePath) {
        for (String file : filePath) {
            return deleteFile(file);
        }
        return true;
    }


    /**
     * 对文件名进行截取文件后缀
     *
     * @param fileName
     * @return
     */
    public static String getSuffix(String fileName) {
        //获取最后一个点的下标
        int index = fileName.lastIndexOf(".");
        if (index != -1) {
            //从点的下标开始截取
            return fileName.substring(index);
        }
        throw new RuntimeException("文件无后缀");
    }

    /**
     * 随机字符串
     *
     * @return
     */
    public static String createUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 创建年月日路径目录
     *
     * @param pictureType 图片类型
     * @return
     */
    private static String createDateDirectory(String pictureType) {
        //完整的存储路径
        String yearToDatePath = "";

        //创建时间对象
        Calendar cal = Calendar.getInstance();
        //获取完整的本地年路径
        Path pathYear = getYearPath(pictureType, cal);

        //获取月目录字符串
        String monthStr = getMonthStr(pathYear, cal);
        //获取完整的本地月路径
        Path pathMonth = Paths.get(monthStr);//创建月路径目录对象

        //获取日目录字符串
        String pathDayStr = getDayStr(monthStr, cal);//创建日路径目录对象
        //获取完整的本地日路径
        Path pathDay = Paths.get(pathDayStr);//创建日路径目录对象

        if (!Files.exists(pathYear)) {//年目录不存在
            try {
                //年目录创建
                Files.createDirectory(pathYear);
                yearToDatePath = pathDayStr;
                //月目录创建
                if (!Files.exists(pathMonth)) {
                    try {
                        Files.createDirectory(pathMonth);//月目录创建成功
                        yearToDatePath = pathDayStr;
                        //日期目录创建(里层不用再else中嵌套)
                        if (!Files.exists(pathDay)) {
                            try {
                                Files.createDirectory(pathDay);//创建日目录
                                yearToDatePath = pathDayStr;
                                System.out.println("日创建成功");
                            } catch (Exception e) {
                                e.printStackTrace();
                                //日目录创建失败
                                yearToDatePath = null;
                            }
                        } else {
                            yearToDatePath = pathDayStr;//日目录已经存在(也返回)
                            System.out.println("日目录已经存在");
                        }
                    } catch (Exception e) {
                        yearToDatePath = null;
                        System.out.println("月目录创建失败：" + e.getMessage());
                    }
                } else {
                    yearToDatePath = pathDayStr;//月目录已经存在
                    //System.out.println("月目录已经存在");
                }

            } catch (Exception e) {
                yearToDatePath = null;
                System.out.println("年目录创建失败：" + e.getMessage());
            }
        } else {//年目录存在时
            //System.out.println("年目录已经存在");
            //月目录创建
            if (!Files.exists(pathMonth)) {
                try {
                    Files.createDirectory(pathMonth);
                    yearToDatePath = pathDayStr;
                    System.out.println("月目录创建成功");

                    //日期目录创建(里层不用再else中嵌套)
                    if (!Files.exists(pathDay)) {
                        try {
                            Files.createDirectory(pathDay);//日目录创建成功
                            System.out.println("日创建成功");
                            yearToDatePath = pathDayStr;
                        } catch (Exception e) {
                            e.printStackTrace();
                            yearToDatePath = null;
                        }
                    } else {
                        yearToDatePath = pathDayStr;//日目录已经存在
                        System.out.println("日目录已存在");
                    }
                } catch (Exception e) {
                    System.out.println("月目录创建失败：" + e.getMessage());
                }

            } else {
                //System.out.println("月目录已经存在");
                yearToDatePath = pathDayStr;
                if (!Files.exists(pathDay)) {
                    try {
                        Files.createDirectory(pathDay);//日目录创建成功
                        System.out.println("日创建成功");
                        yearToDatePath = pathDayStr;
                    } catch (Exception e) {
                        e.printStackTrace();
                        yearToDatePath = null;
                    }
                } else {
                    yearToDatePath = pathDayStr;//日目录已经存在
                    System.out.println("日目录已存在");
                }
            }
        }
        return yearToDatePath + "\\";
    }

    /**
     * 获取日目录的绝对路径字符串
     *
     * @param pathMonthStr 月路径字符串
     * @param cal          时间对象
     * @return 返回Path对象
     */
    private static String getDayStr(String pathMonthStr, Calendar cal) {
        //创建日路径目录对象
        int day = cal.get(Calendar.DAY_OF_MONTH);
        String pathDayStr = pathMonthStr + "\\" + day;//日路径
        return pathDayStr;
    }

    /**
     * 获取月目录的绝对路径字符串
     *
     * @param pathYear 年路径对象
     * @param cal      时间对象
     * @return 返回Path对象
     */
    private static String getMonthStr(Path pathYear, Calendar cal) {
        //创建月路径目录对象
        int month = cal.get(Calendar.MONTH);
        //月路径字符串
        String pathMonthStr = pathYear + "\\" + (month + 1);
        return pathMonthStr;
    }

    /**
     * 获取年目录的绝对路径
     *
     * @param pictureType 图片类型
     * @param cal         时间对象
     * @return 返回Path对象
     */
    private static Path getYearPath(String pictureType, Calendar cal) {
        //创建年路径目录对象
        int year = cal.get(Calendar.YEAR);
        Path pathYear = Paths.get("");
        if (pictureType.equals("头像")) {
            //这段字符串路径要真实存在在硬盘上(最后一段就是要创建的目录(year))
            String projectPath = FILE_PATH + "images\\headPortrait\\" + year;
            pathYear = Paths.get(projectPath);//创建年路径目录对象
        }
        if (pictureType.equals("菜品")) {
            String projectPath = FILE_PATH + "images\\menu\\" + year;
            pathYear = Paths.get(projectPath);//创建年路径目录对象
        }
        if (pictureType.equals("套餐")) {
            String projectPath = FILE_PATH + "images\\setMeal\\" + year;
            pathYear = Paths.get(projectPath);//创建年路径目录对象
        }
        if (pictureType.equals("广告")) {
            String projectPath = FILE_PATH + "images\\advertise\\" + year;
            pathYear = Paths.get(projectPath);//创建年路径目录对象
        }
        if (pictureType.equals("优惠券")) {
            String projectPath = FILE_PATH + "images\\coupon\\" + year;
            pathYear = Paths.get(projectPath);//创建年路径目录对象
        }
        return pathYear;
    }


}
